(function($){
    $.fn.editable=function(target,options){
        if('disable'==target){
            $(this).data('disabled.editable',true);
            return;
        }
        if('enable'==target){
            $(this).data('disabled.editable',false);
            return;
        }
        if('destroy'==target){
            $(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');
            return;
        }
        var settings=$.extend({},$.fn.editable.defaults,{
            target:target
        },options);
        var plugin=$.editable.types[settings.type].plugin||function(){};
        
        var submit=$.editable.types[settings.type].submit||function(){};
        
        var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;
        var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;
        var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;
        var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;
        var callback=settings.callback||function(){};
        
        var onedit=settings.onedit||function(){};
        
        var onsubmit=settings.onsubmit||function(){};
        
        var onreset=settings.onreset||function(){};
        
        var onerror=settings.onerror||reset;
        if(settings.tooltip){
            $(this).attr('title',settings.tooltip);
        }
        settings.autowidth='auto'==settings.width;
        settings.autoheight='auto'==settings.height;
        return this.each(function(){
            var self=this;
            var savedwidth=$(self).width();
            var savedheight=$(self).height();
            $(this).data('event.editable',settings.event);
            if(!$.trim($(this).html())){
                $(this).html(settings.placeholder);
            }
            $(this).bind(settings.event,function(e){
                if(true===$(this).data('disabled.editable')){
                    return;
                }
                if(self.editing){
                    return;
                }
                if(false===onedit.apply(this,[settings,self])){
                    return;
                }
                e.preventDefault();
                e.stopPropagation();
                if(settings.tooltip){
                    $(self).removeAttr('title');
                }
                if(0==$(self).width()){
                    settings.width=savedwidth;
                    settings.height=savedheight;
                }else{
                    if(settings.width!='none'){
                        settings.width=settings.autowidth?$(self).width():settings.width;
                    }
                    if(settings.height!='none'){
                        settings.height=settings.autoheight?$(self).height():settings.height;
                    }
                }
                if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){
                    $(this).html('');
                }
                self.editing=true;
                self.revert=$(self).html();
                $(self).html('');
                var form=$('<form />');
                if(settings.cssclass){
                    if('inherit'==settings.cssclass){
                        form.attr('class',$(self).attr('class'));
                    }else{
                        form.attr('class',settings.cssclass);
                    }
                }
                if(settings.formid){
                    form.attr('id',settings.formid);
                }
                if(settings.style){
                    if('inherit'==settings.style){
                        form.attr('style',$(self).attr('style'));
                        form.css('display',$(self).css('display'));
                    }else{
                        form.attr('style',settings.style);
                    }
                }
                var input=element.apply(form,[settings,self]);
                var input_content;
                if(settings.loadurl){
                    var t=setTimeout(function(){
                        input.disabled=true;
                        content.apply(form,[settings.loadtext,settings,self]);
                    },100);
                    var loaddata={};
            
                    loaddata[settings.id]=self.id;
                    if($.isFunction(settings.loaddata)){
                        $.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));
                    }else{
                        $.extend(loaddata,settings.loaddata);
                    }
                    $.ajax({
                        type:settings.loadtype,
                        url:settings.loadurl,
                        data:loaddata,
                        async:false,
                        success:function(result){
                            window.clearTimeout(t);
                            input_content=result;
                            input.disabled=false;
                        }
                    });
                }else if(settings.data){
                    input_content=settings.data;
                    if($.isFunction(settings.data)){
                        input_content=settings.data.apply(self,[self.revert,settings]);
                    }
                }else{
                    input_content=self.revert;
                }
                content.apply(form,[input_content,settings,self]);
                input.attr('name',settings.name);
                buttons.apply(form,[settings,self]);
                $(self).append(form);
                plugin.apply(form,[settings,self]);
                $(':input:visible:enabled:first',form).focus();
                if(settings.select){
                    input.select();
                }
                input.keydown(function(e){
                    if(e.keyCode==27){
                        e.preventDefault();
                        reset.apply(form,[settings,self]);
                    }
                });
                var t;
                if('cancel'==settings.onblur){
                    input.blur(function(e){
                        t=setTimeout(function(){
                            reset.apply(form,[settings,self]);
                        },500);
                    });
                }else if('submit'==settings.onblur){
                    input.blur(function(e){
                        t=setTimeout(function(){
                            form.submit();
                        },200);
                    });
                }else if($.isFunction(settings.onblur)){
                    input.blur(function(e){
                        settings.onblur.apply(self,[input.val(),settings]);
                    });
                }else{
                    input.blur(function(e){});
                }
                form.submit(function(e){
                    if(t){
                        clearTimeout(t);
                    }
                    e.preventDefault();
                    if(false!==onsubmit.apply(form,[settings,self])){
                        if(false!==submit.apply(form,[settings,self])){
                            if($.isFunction(settings.target)){
                                var str=settings.target.apply(self,[input.val(),settings]);
                                $(self).html(str);
                                self.editing=false;
                                callback.apply(self,[self.innerHTML,settings]);
                                if(!$.trim($(self).html())){
                                    $(self).html(settings.placeholder);
                                }
                            }else{
                                var submitdata={};
                                var input_hidden=element.apply(form,[settings,self]);
                                input_hidden.attr('name','id');
                                input_hidden.attr('id','id');
                                submitdata[settings.name]=input.val();
                                submitdata[settings.id]=self.id;
                                
                                if($.isFunction(settings.submitdata)){
                                    $.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));
                                }else{
                                    $.extend(submitdata,settings.submitdata);
                                }
                                if('PUT'==settings.method){
                                    submitdata['_method']='put';
                                }
                                $(self).html(settings.indicator);
                                submitdata['id']=input_hidden.val();
                                var ajaxoptions={
                                    type:'POST',
                                    data:submitdata,
                                    dataType:'html',
                                    url:settings.target,
                                    success:function(result,status){
                                        if(ajaxoptions.dataType=='html'){
                                            $(self).html(result);
                                        }
                                        self.editing=false;
                                        callback.apply(self,[result,settings]);
                                        if(!$.trim($(self).html())){
                                            $(self).html(settings.placeholder);
                                        }
                                    },
                                    error:function(xhr,status,error){
                                        onerror.apply(form,[settings,self,xhr]);
                                    }
                                };
        
                                $.extend(ajaxoptions,settings.ajaxoptions);
                                $.ajax(ajaxoptions);
                            }
                        }
                    }
                    $(self).attr('title',settings.tooltip);
                    return false;
                });
            });
            this.reset=function(form){
                if(this.editing){
                    if(false!==onreset.apply(form,[settings,self])){
                        $(self).html(self.revert);
                        self.editing=false;
                        if(!$.trim($(self).html())){
                            $(self).html(settings.placeholder);
                        }
                        if(settings.tooltip){
                            $(self).attr('title',settings.tooltip);
                        }
                    }
                }
            };

        });
    };

    $.editable={
        types:{
            defaults:{
                element:function(settings,original){
                    var input=$('<input type="hidden"></input>');
                    $(this).append(input);
                    return(input);
                },
                content:function(string,settings,original){
                    $(':input:first',this).val(string);
                },
                reset:function(settings,original){
                    original.reset(this);
                },
                buttons:function(settings,original){
                    var form=this;
                    if(settings.submit){
                        if(settings.submit.match(/>$/)){
                            var submit=$(settings.submit).click(function(){
                                if(submit.attr("type")!="submit"){
                                    form.submit();
                                }
                            });
                        }else{
                            var submit=$('<button type="submit" />');
                            submit.html(settings.submit);
                        }
                        $(this).append(submit);
                    }
                    if(settings.cancel){
                        if(settings.cancel.match(/>$/)){
                            var cancel=$(settings.cancel);
                        }else{
                            var cancel=$('<button type="cancel" />');
                            cancel.html(settings.cancel);
                        }
                        $(this).append(cancel);
                        $(cancel).click(function(event){
                            if($.isFunction($.editable.types[settings.type].reset)){
                                var reset=$.editable.types[settings.type].reset;
                            }else{
                                var reset=$.editable.types['defaults'].reset;
                            }
                            reset.apply(form,[settings,original]);
                            return false;
                        });
                    }
                }
            },
            text:{
                element:function(settings,original){
                    var input=$('<input />');
                    if(settings.width!='none'){
                        input.width(settings.width);
                    }
                    if(settings.height!='none'){
                        input.height(settings.height);
                    }
                    input.attr('autocomplete','off');
                    $(this).append(input);
                    return(input);
                }
            },
            textarea:{
                element:function(settings,original){
                    var textarea=$('<textarea />');
                    if(settings.rows){
                        textarea.attr('rows',settings.rows);
                    }else if(settings.height!="none"){
                        textarea.height(settings.height);
                    }
                    if(settings.cols){
                        textarea.attr('cols',settings.cols);
                    }else if(settings.width!="none"){
                        textarea.width(settings.width);
                    }
                    $(this).append(textarea);
                    return(textarea);
                }
            },
            select:{
                element:function(settings,original){
                    var select=$('<select />');
                    $(this).append(select);
                    return(select);
                },
                content:function(data,settings,original){
                    if(String==data.constructor){
                        eval('var json = '+data);
                    }else{
                        var json=data;
                    }
                    for(var key in json){
                        if(!json.hasOwnProperty(key)){
                            continue;
                        }
                        if('selected'==key){
                            continue;
                        }
                        var option=$('<option />').val(key).append(json[key]);
                        $('select',this).append(option);
                    }
                    $('select',this).children().each(function(){
                        if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){
                            $(this).attr('selected','selected');
                        }
                    });
                }
            }
        },
        addInputType:function(name,input){
            $.editable.types[name]=input;
        }
    };

    $.fn.editable.defaults={
        name:'value',
        id:'id',
        type:'text',
        width:'auto',
        height:'auto',
        event:'click.editable',
        onblur:'cancel',
        loadtype:'GET',
        loadtext:'Loading...',
        placeholder:'Click to edit',
        loaddata:{},
        submitdata:{},
        ajaxoptions:{}
    };

})(jQuery);

